<?php
namespace PsiFramework\Classes\Util\HTTP;

import("Classes.DAO.ConnectionDAO");
import("Classes.Model.SessionUser");
import("Classes.Util.HTTP.Connection");
import("Classes.Util.HTTP.Session");

use \PsiFramework\Classes\DAO\ConnectionDAO;
use \PsiFramework\Classes\Model\SessionUser;
use \PsiFramework\Classes\Util\HTTP\Connection;
use \PsiFramework\Classes\Util\HTTP\Request;
use \PsiFramework\Classes\Util\HTTP\Session;
use \PsiFramework\Classes\Util\Object\Date;
use \PsiFramework\Classes\Util\Security\Manager\SecurityManager;

/**
 * PsiFramework
 * Php Simple Framework
 *
 * @author Rémi San
 * @version beta
 */

/**
 * The AuthenticationManager class is used to manage the user authentication
 *
 * @package Util.HTTP
 */
class AuthenticationManager
{

    protected static            $_singleton = null;
    public static /*int*/     $timeOut = null ; //timeout in seconds

    protected /*Session*/       $_session ;
    protected /*Request*/       $_request ;
    protected /*ConnectionDAO*/ $_connectionDao ;
    protected /*SessionUser*/   $_authenticatedUser ;

    /**
     * Constructor
     *
     * @return    AuthenticationManager    instance
     */
    protected function __construct()
    {
        $this->_request = Request::getInstance();
        $this->_session = Session::getInstance();
        $this->_authenticatedUser = null ;
        $this->_connectionDao = ConnectionDAO::getInstance();
        $this->init();
    }

    protected function init()
    {

        //Deletes the old connections
        if (!isNullOrEmptyString(self::$timeOut) && self::$timeOut > 0) {
            $this->_connectionDao->deleteOldConnections(self::$timeOut);
        }

        //update the session last seen if the user is authenticated
        $this->_authenticatedUser = $this->_session->get("authenticated_user");

        if ($this->_authenticatedUser != null) {
            $connection
                = $this->_connectionDao->findConnectionBySession(
                    $this->_session->getId()
                );//we retrieve the connection information
            if ($connection != null) {
                //if the connection has been retrieved
                //we check if the session is still on the same ip and user ;
                if ($connection->getUser()->getId() == $this->_authenticatedUser->getId()
                    && $connection->getIpAddress() == $this->_request->getIP()
                ) {
                    //we check if the session has not timed out
                    $timeSinceLastAction
                        = $connection->getLastSeen()->getTimePassed(Date::now());
                    if (isNullOrEmptyString(self::$timeOut)
                        || self::$timeOut == 0
                        || $timeSinceLastAction<self::$timeOut
                    ) {
                        //if the time is inferior to the timeout
                        //we update the last seen time
                        $this->_connectionDao->update($connection);
                    } else { //if the time is superior to the timeout
                        //we force the disconnection and
                        //delete the connection information
                        $this->disconnect();
                    }
                } else {
                    //gestion de l'usurpation
                    $this->disconnect();
                }
            } else {
                //we force the disconnection
                $this->disconnect();
            }
            $connection = null ; //free the variable
        } else {
            //we force the disconnection
            $this->disconnect();
        }
    }

    public function connect($user)
    {
        SecurityManager::reset();
        $sessionUser = new SessionUser(
            $user->getId(),
            $user->getLogin(),
            $user->getPassword()
        );
        $this->_authenticatedUser = $sessionUser ;
        $this->_session->set("authenticated_user", $sessionUser);
        $this->_connectionDao->save(
            new Connection(
                $sessionUser,
                $this->_session->getId(),
                $this->_request->getIP(),
                Date::now()
            )
        );
    }

    public function disconnect()
    {
        $this->_authenticatedUser = null ;
        $this->_session->set("authenticated_user", null);
        $connection = new Connection(null, $this->_session->getId());
        $this->_connectionDao->delete($connection);
        SecurityManager::reset();
    }

    public function getAuthenticatedUser()
    {
        return $this->_authenticatedUser ;
    }

    /**
     * Function to be called instead of the constructor.
     *
     * @return     AuthenticationManager instance
     */
    public static function getInstance()
    {

        if (self::$_singleton==null) {
            self::$_singleton = new AuthenticationManager();
        }

        return self::$_singleton;
    }
}
